<template>
  <div class="play">
    <audio
      ref="music"
      autoplay
      v-if="curSong"
      :src="`https://music.163.com/song/media/outer/url?id=${curSong.id}.mp3`"
      @timeupdate="timeUpdate"
      @play="playFlag = true"
      @pause="playFlag = false"
      @canplay="canplay"
      @ended="ended"
    ></audio>
    <div class="miniBar" @click="openFullScreen">
      <div class="left">
        <div class="pic">
          <img v-if="picUrl" :src="picUrl" />
          <img v-if="!picUrl" src="../assets/logo_min.png" />
        </div>
        <div class="middle">
          <div class="name">{{ curSong ? curSong.name : "XX音乐" }}</div>
          <span class="time" v-if="curSong">{{ curTime | formatTime }}</span>
          <div class="prWrap" @click="changeProgress" data-no="true">
            <div class="progress">
              <div class="bar" :style="{ width: progress + '%' }"></div>
            </div>
          </div>
        </div>
      </div>
      <div class="right">
        <div class="prev" @click="prevMusic" data-no="true"></div>
        <div
          :class="{ playBtn: !playFlag, pauseBtn: playFlag }"
          @click="playMusic"
          data-no="true"
        ></div>
        <div class="next" @click="nextMusic" data-no="true"></div>
      </div>
    </div>
    <transition
      enter-active-class="animate__animated animate__fadeInUp"
      leave-active-class="animate__animated animate__fadeOutDown"
    >
      <div class="fullScreen" v-show="showScreen" @touchmove.prevent>
        <img class="bg" v-if="picUrl" :src="picUrl" />
        <img class="bg" v-if="!picUrl" src="../assets/logo_min.png" />
        <div class="top">
          <div class="title">
            <div class="name">{{ curSong ? curSong.name : "" }}</div>
            <div class="artist" v-if="curSong">
              {{ curSong.ar | getArtists }}
            </div>
          </div>

          <div class="backBtn" @click="showScreen = false"></div>
        </div>
        <div class="pic">
          <img v-if="picUrl" :src="picUrl" />
          <img v-if="!picUrl" src="../assets/logo_min.png" />
        </div>
        <div
          class="lyric"
          ref="lyric"
          @touchstart="lyTouchStart"
          @touchmove="lyTouchMove"
          @touchend="lyTouchEnd"
        >
          <ul :style="{ top }">
            <li
              v-for="(item, index) in curLyric"
              :key="index"
              :class="{ active: index == lyricIndex }"
              :ref="index"
              :data-time="item.time"
            >
              <span>{{ item.lyric }}</span>
            </li>
          </ul>
          <div class="line" v-show="tDown">
            <span>{{ curTime | formatTime }}</span>
          </div>
        </div>
        <p class="time">
          <span>{{ curSong ? $options.filters.formatTime(curTime) : "" }}</span>
          <span>{{ curSong ? $options.filters.formatTime(durTime) : "" }}</span>
        </p>
        <div
          class="prWrap"
          @touchstart="prTouchStart"
          @touchend="prTouchEnd"
          ref="progress"
        >
          <div class="progress">
            <div class="bar" :style="{ width: progress + '%' }"></div>
            <div class="dot" :style="{ left: progress + '%' }"></div>
          </div>
        </div>
        <div class="bottom">
          <div
            :class="loopType[loopIndex]"
            @click="loopIndex = ++loopIndex > 2 ? 0 : loopIndex"
          ></div>
          <div class="prevBtn" @click="prevMusic"></div>
          <div
            :class="{ playBtn: !playFlag, pauseBtn: playFlag }"
            @click="playMusic"
          ></div>
          <div class="nextBtn" @click="nextMusic"></div>
          <div class="listBtn" @click="showPlayList = !showPlayList"></div>
        </div>
      </div>
    </transition>
    <PlayList
      :playList="playList"
      :curIndex="listIndex"
      :show="showPlayList"
      @closeList="showPlayList = false"
      @clickPlayList="clickPlayList"
      @deleteSong="deleteSong"
    ></PlayList>
  </div>
</template>

<script>
import PlayList from "@/components/PlayList";
export default {
  name: "Play",
  data() {
    return {
      picUrl: null,
      showScreen: false,
      progress: 0,
      playFlag: false,
      curIndex: null,
      curSong: null,
      curTime: null,
      durTime: null,
      randomList: null,
      curLyric: null,
      loopType: ["singleloop", "listloop", "random"],
      loopIndex: 0,
      lyricIndex: 0,
      top: "0px",
      tDown: false,
      showPlayList: false,
    };
  },
  props: {
    songList: {
      type: Object,
      default: null,
    },
    showPlay: Boolean,
  },
  watch: {
    showPlay(val) {
      if (!val && this.$refs.music) {
        this.$refs.music.pause();
      }
    },
    songList(val) {
      this.curIndex = val.curIndex;
      this.getRanList();
      this.getMusicInfo();
      this.getLyric();
    },
    curSong(val) {
      this.picUrl = null;
      this.durTime = null;
      this.curTime = null;
      this.progress = 0;
      if (!val) return;
      this.img = new Image();
      this.img.src = val.al.picUrl;
      this.img.onload = () => {
        if (!this.img) return;
        this.picUrl = this.img.src;
      };
    },
    curIndex(val) {
      if (val == null) return;
      this.getMusicInfo();
      this.getLyric();
    },
    loopIndex() {
      this.getRanList();
    },
  },
  computed: {
    playList() {
      var list = {
        artists: [],
        name: [],
      };
      if (!this.songList) return;
      if (this.loopIndex == 2) {
        this.randomList.forEach((i) => {
          list.artists.push(this.songList.arList[i]);
          list.name.push(this.songList.nameList[i]);
        });
      } else {
        list.artists = this.songList.arList;
        list.name = this.songList.nameList;
      }
      return list;
    },
    listIndex() {
      if (!this.songList) return;
      return this.loopIndex == 2
        ? parseInt(this.randomList.indexOf(String(this.curIndex)))
        : this.curIndex;
    },
  },
  methods: {
    getMusicInfo() {
      // console.log(this.songList.idList[this.curIndex]);
      let ids = this.songList.idList[this.curIndex];
      if (this.curSong && ids == this.curSong.id) return;
      this.curSong = null;
      if (!ids) return;
      if (this.curGetInfo == ids) return; // 防止重复获取
      this.curGetInfo = ids;
      console.log(ids);
      this.$http
        .get("/song/detail", {
          params: {
            ids: ids,
          },
        })
        .then((d) => {
          if (this.curGetInfo == ids) {
            this.curSong = d.data.songs[0];
            this.curGetInfo = null;
          }
        })
        .catch(console.log);
    },
    getLyric() {
      let ids = this.songList.idList[this.curIndex];
      if (this.curSong && ids == this.curSong.id) return;
      this.curLyric = null;
      if (!ids) return;
      if (this.curGetLyric == ids) return; // 防止重复获取
      this.curGetLyric = ids;
      this.$http
        .get("/lyric", {
          params: {
            id: ids,
          },
        })
        .then((d) => {
          // console.log(d.data.lrc.lyric);
          let arr = ["[00:00.000] 该歌曲暂无歌词", ""];
          let reg = /\[(\d+):(\d+\.\d+)\](.*)/;
          if (d.data.lrc && d.data.lrc.lyric.length > 0) {
            let newArr = d.data.lrc.lyric.split("\n");
            if (!newArr.every((a) => !reg.test(a))) {
              arr = newArr;
            }
          }
          arr.pop();
          // console.log(arr);
          // [00:00.000] 作词 :
          // [00:01.000] 作曲 :
          if (this.curGetLyric == ids) {
            this.curLyric = arr
              .map((lc) => {
                if (reg.test(lc)) {
                  return {
                    time: (
                      parseInt(RegExp.$1 * 60) + parseFloat(RegExp.$2)
                    ).toFixed(2),
                    lyric: RegExp.$3,
                  };
                }
              })
              .filter((a) => a && a.lyric != "");
            this.curGetLyric = null;
          }
        })
        .catch(console.log);
    },
    timeUpdate(e) {
      if (!this.curSong) return;
      this.curTime = e.target.currentTime;
      var pr = this.curTime / this.durTime;
      this.progress = pr ? pr * 100 : 0;
      this.moveLyrics();
    },
    canplay(e) {
      this.curTime = e.target.currentTime;
      this.durTime = e.target.duration;
    },
    ended() {
      if (this.tDown) return;
      let au = this.$refs.music;
      switch (this.loopIndex) {
        case 0:
          au.currentTime = 0;
          au.play();
          break;
        case 1:
        case 2:
          this.nextMusic();
          break;
      }
    },
    playMusic() {
      if (!this.curSong || !this.durTime) return;
      var au = this.$refs.music;
      this.playFlag ? au.pause() : au.play();
    },
    prevMusic() {
      if (!this.curSong) return;
      this.progress = 0;
      if (this.songList.idList.length == 0) {
        this.curSong = null;
        this.picUrl = null;
        this.img = null;
        this.curLyric = null;
        this.durTime = null;
        this.curTime = null;
        return;
      }
      if (this.songList.idList.length == 1) this.$refs.music.currentTime = 0;
      var index = this.curIndex - 1;
      this.curIndex = index < 0 ? this.songList.idList.length - 1 : index;
    },
    nextMusic() {
      if (!this.curSong) return;
      this.progress = 0;
      if (this.songList.idList.length == 0) {
        this.curSong = null;
        this.curIndex = null;
        this.picUrl = null;
        this.img = null;
        this.curLyric = null;
        this.durTime = null;
        this.curTime = null;
        return;
      }
      if (this.songList.idList.length == 1) this.$refs.music.currentTime = 0;
      if (this.loopIndex == 2) {
        var l = this.randomList;
        for (var i = 0; i < l.length; i++) {
          if (l[i] == this.curIndex) {
            this.curIndex = parseInt(l[i + 1 >= l.length ? 0 : i + 1]);
            // console.log(this.curIndex);
            break;
          }
        }
      } else {
        var index = this.curIndex + 1;
        this.curIndex = index >= this.songList.idList.length ? 0 : index;
      }
    },
    getRanList() {
      if (!this.songList) return;
      if (this.loopIndex == 2) {
        let ranArr = Object.keys(this.songList.idList)
          .filter((a) => a != this.curIndex)
          .sort(() => Math.random() - 0.5);
        this.randomList = ranArr
          .slice(0, this.curIndex)
          .concat(String(this.curIndex), ranArr.slice(this.curIndex));
        // console.log(this.randomList);
      }
    },
    changeProgress(e) {
      if (!this.curSong || !this.durTime) return;
      var progress = e.offsetX / e.target.clientWidth;
      var au = this.$refs.music;
      au.currentTime = progress * this.durTime;
      // console.log(au.currentTime);
    },
    prTouchStart(e) {
      if (!this.curSong || !this.durTime) return;
      this.tDown = true;
      var pageX = e.targetTouches[0].pageX;
      var left = e.target.offsetLeft;
      var ofX = (pageX - left) / e.target.clientWidth;
      var curProgress = Math.max(0, Math.min(100, ofX * 100));
      var au = this.$refs.music;
      au.currentTime = (curProgress / 100) * this.durTime;
      var _this = this;
      e.target.ontouchmove = function (e) {
        if (!_this.curSong && !_this.durTime) return;
        var dtX = e.targetTouches[0].pageX - pageX;
        var dtP = (dtX / _this.$refs.progress.clientWidth) * 100;
        var curPr = Math.max(0, Math.min(100, curProgress + dtP));
        au.currentTime = (curPr / 100) * _this.durTime;
      };
    },
    prTouchEnd() {
      this.tDown = false;
    },
    openFullScreen(e) {
      if (!e.target.dataset.no) {
        this.showScreen = true;
        this.$nextTick(() => {
          this.moveLyrics();
        });
      }
    },
    moveLyrics() {
      var t = this.curTime;
      if (!this.curLyric) return;
      for (var i = 0; i < this.curLyric.length; i++) {
        if (i == this.curLyric.length - 1) {
          this.lyricIndex = i;
          break;
        }
        if (t >= this.curLyric[i].time && t < this.curLyric[i + 1].time) {
          this.lyricIndex = i;
          break;
        }
      }
      if (!this.$refs[this.lyricIndex] || !this.$refs[this.lyricIndex][0])
        return;
      this.top = this.getLyricTop(this.lyricIndex) + "px";
    },
    getLyricTop(index) {
      return (
        -this.$refs[index][0].offsetTop +
        this.$refs.lyric.clientHeight / 2 -
        this.$refs[index][0].clientHeight / 2
      );
    },
    lyTouchStart(e) {
      if (!this.curSong || !this.durTime || !this.curLyric) return;
      this.tDown = true;
      this.$refs.music.pause();
      this.py = e.targetTouches[0].pageY;
      this.curTop = parseFloat(this.top);
    },
    lyTouchMove(e) {
      if (!this.curSong || !this.durTime || !this.curLyric) return;
      let dty = e.changedTouches[0].pageY - this.py;
      let firstY = this.getLyricTop(0);
      let lastY = this.getLyricTop(this.curLyric.length - 1);
      let nowTop = Math.max(lastY, Math.min(firstY, this.curTop + dty));
      this.top = nowTop + "px";
      for (var i = this.curLyric.length - 1; i >= 0; i--) {
        var tempTop =
          -this.$refs[i][0].offsetTop + this.$refs.lyric.clientHeight / 2;
        if (nowTop < tempTop) {
          this.lyricIndex = i;
          this.curTime = this.$refs[i][0].dataset.time;
          break;
        }
      }
    },
    lyTouchEnd() {
      this.tDown = false;
      if (!this.curSong || !this.durTime || !this.curLyric) return;
      this.$refs.music.currentTime = this.$refs[
        this.lyricIndex
      ][0].dataset.time;
      this.$refs.music.play();
    },
    clickPlayList(e) {
      var index = e;
      if (this.loopIndex == 2) {
        index = parseInt(this.randomList[e]);
      }
      this.curIndex = index;
    },
    deleteSong(index) {
      if (this.loopIndex == 2) {
        index = parseInt(this.randomList[index]);
      }
      if (this.curIndex == index) {
        this.nextMusic();
      }
      this.$nextTick(() => {
        this.songList.arList.splice(index, 1);
        this.songList.idList.splice(index, 1);
        this.songList.nameList.splice(index, 1);
        if (this.loopIndex == 2) {
          this.randomList = this.randomList
            .filter((a) => a != index)
            .map((a) => (a > index ? String(a - 1) : a));
          // console.log(this.randomList);
        }
        this.curIndex =
          this.curIndex > index ? this.curIndex - 1 : this.curIndex;
        if (this.songList.idList.length == 0) this.nextMusic();
      });
    },
  },
  filters: {
    formatTime(t) {
      if (t == null) return "";
      var m = parseInt(t / 60);
      var s = parseInt(t % 60);
      return (m < 10 ? "0" + m : m) + ":" + (s < 10 ? "0" + s : s);
    },
    getArtists(val) {
      if (!val) return "";
      return val.map((item) => item.name).join(" / ");
    },
  },
  components: {
    PlayList,
  },
};
</script>

<style lang="less" scoped>
.play {
  position: fixed;
  bottom: 0;
  left: 0;
  width: 100%;
  background-color: #fff;
  box-shadow: 0 0 20px 0 rgba(0, 0, 0, 0.1);
  z-index: 999;
  audio {
    display: none;
    width: 100%;
    vertical-align: bottom;
  }
  .miniBar {
    height: 60px;
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 0 10px;
    .left {
      flex: 1;
      display: flex;
      .pic {
        width: 45px;
        height: 45px;
        border-radius: 50%;
        margin: 0 10px;
        background: #efffff;
        overflow: hidden;
        img {
          width: 100%;
        }
      }
      .middle {
        width: 0;
        flex: 1;
        margin-right: 10px;
        display: flex;
        flex-direction: column;
        justify-content: space-between;
        position: relative;
        .name {
          width: 100%;
          font-size: 16px;
          white-space: nowrap;
          overflow: hidden;
          text-overflow: ellipsis;
          margin-top: 4px;
        }
        .time {
          position: absolute;
          color: #ccc;
          font-size: 12px;
          right: 0;
          top: 50%;
          transform: scale(0.8);
          transform-origin: right;
          pointer-events: none;
        }
        .prWrap {
          width: 100%;
          height: 15px;
          display: flex;
          align-items: center;
          .progress {
            width: 100%;
            height: 4px;
            border-radius: 2px;
            overflow: hidden;
            background: #eee;
            pointer-events: none;
            .bar {
              height: 100%;
              border-radius: 2px;
              background-color: #bbb;
            }
          }
        }
      }
    }
    .right {
      width: 110px;
      height: 60px;
      margin: 0 5px;
      box-sizing: border-box;
      display: flex;
      align-items: center;
      justify-content: space-between;
      .playBtn,
      .pauseBtn {
        width: 35px;
        height: 35px;
        background-size: contain;
        &.playBtn {
          background-image: url(../assets/music_play.png);
        }
        &.pauseBtn {
          background-image: url(../assets/music_pause.png);
        }
      }
      .next,
      .prev {
        width: 23px;
        height: 23px;
        background: #ccc;
        background: url(../assets/music_next.png);
        background-size: contain;
        &.prev {
          transform: scaleX(-1);
        }
      }
    }
  }
  .fullScreen {
    position: fixed;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
    overflow: hidden;
    background: #fcfcfd;
    z-index: 99;
    animation-duration: 0.8s;
    display: flex;
    flex-direction: column;
    .bg {
      height: 100%;
      background: #eee;
      position: absolute;
      z-index: -1;
      left: 50%;
      transform: translateX(-50%);
      opacity: 0.3;
      filter: blur(30vw);
    }
    .top {
      height: 60px;
      position: relative;
      display: flex;
      justify-content: center;
      align-items: center;
      &::after {
        content: "";
        display: block;
        width: 100%;
        height: 80px;
        background: linear-gradient(
          rgba(255, 255, 255, 0.4) 10%,
          rgba(0, 0, 0, 0) 100%
        );
        position: absolute;
        z-index: -1;
        top: 0;
        left: 0;
      }
      .title {
        position: relative;
        .name {
          font-size: 16px;
          max-width: 66vw;
          white-space: nowrap;
          overflow: hidden;
          text-overflow: ellipsis;
        }
        .artist {
          max-width: 60vw;
          white-space: nowrap;
          overflow: hidden;
          text-overflow: ellipsis;
          position: absolute;
          z-index: 99;
          height: 12px;
          line-height: 12px;
          bottom: -12px;
          left: 50%;
          transform: translateX(-50%);
          text-align: center;
          font-size: 12px;
          color: #999;
        }
      }
      .backBtn {
        width: 20px;
        height: 20px;
        position: absolute;
        top: 50%;
        left: 20px;
        background: url("../assets/back.png");
        background-size: 100%;
        transform: translateY(-50%);
      }
    }
    .pic {
      width: 34vh;
      max-width: 60vw;
      flex: 7;
      display: flex;
      align-items: center;
      margin: auto;
      overflow: hidden;
      img {
        width: 100%;
        border-radius: 50%;
        background: #efffff;
      }
    }
    .lyric {
      width: 100%;
      flex: 3;
      text-align: center;
      overflow: hidden;
      -webkit-mask: -webkit-linear-gradient(
        rgba(0, 0, 0, 0) 0%,
        #000 30%,
        #000 70%,
        rgba(0, 0, 0, 0) 100%
      );
      position: relative;
      margin-bottom: 35px;
      ul {
        width: 100%;
        position: absolute;
        li {
          padding: 0 15%;
          font-size: 13px;
          line-height: 26px;
          font-family: 微软雅黑 Light;
          font-weight: bold;
          span {
            display: block;
            word-break: break-all;
            text-shadow: 0 0 2px rgba(255, 255, 255, 0.3);
            color: #999;
            transition: all 0.5s ease;
            transform-origin: center;
          }
          &.active span {
            text-shadow: 0 0 2px rgba(255, 255, 255, 0.7);
            color: #555;
            transform: scale(1.2);
          }
        }
      }
      .line {
        width: 100%;
        height: 1px;
        background: linear-gradient(
          to right,
          rgba(0, 0, 0, 0) 2%,
          rgba(0, 0, 0, 0.3) 50%,
          rgba(0, 0, 0, 0) 98%
        );
        position: absolute;
        left: 0;
        top: 50%;
        transform: translateY(-50%);
        span {
          font-size: 13px;
          line-height: 15px;
          color: rgba(0, 0, 0, 0.5);
          position: absolute;
          right: 7%;
          top: -15px;
        }
      }
    }
    .time {
      height: 15px;
      line-height: 15px;
      padding: 0 30px;
      display: flex;
      justify-content: space-between;
      font-size: 13px;
      color: #888;
      pointer-events: none;
    }
    .prWrap {
      margin: 0 30px;
      height: 15px;
      display: flex;
      align-items: center;
      .progress {
        width: 100%;
        height: 4px;
        border-radius: 2px;
        background: #eee;
        pointer-events: none;
        position: relative;
        .bar {
          height: 100%;
          border-radius: 2px;
          background-color: #aaa;
        }
        .dot {
          width: 15px;
          height: 15px;
          background: #fff;
          position: absolute;
          border-radius: 50%;
          top: 50%;
          transform: translate(-50%, -50%);
          box-shadow: 0 0 2px #ccc;
        }
      }
    }
    .bottom {
      width: 100%;
      padding: 0 20px;
      box-sizing: border-box;
      display: flex;
      justify-content: space-around;
      margin: 30px 0;
      div {
        width: 40px;
        height: 40px;
        box-sizing: border-box;
        // border: 1px solid #000;
        background-size: 100%;
        background-position: center;
        background-repeat: no-repeat;
      }
      .playBtn {
        background-image: url(../assets/music_play1.png);
      }
      .pauseBtn {
        background-image: url(../assets/music_pause1.png);
      }
      .prevBtn {
        background-image: url(../assets/music_next.png);
        transform: scaleX(-1);
      }
      .nextBtn {
        background-image: url(../assets/music_next.png);
      }
      .listBtn {
        background-image: url(../assets/music_list.png);
        background-size: 50%;
      }
      .singleloop {
        background-image: url(../assets/music_singleloop.png);
        background-size: 60%;
      }
      .listloop {
        background-image: url(../assets/music_listloop.png);
        background-size: 60%;
      }
      .random {
        background-image: url(../assets/music_random.png);
        background-size: 60%;
      }
    }
  }
}
</style>